#include <sys/socket.h>
#include <sys/un.h>
#include <android/log.h>

#include "pthread.h"
#include "unistd.h"

#define LOG_TAG "System.out"//System.out可以修改为其他字符串，该字符串会作为输出日志的TAG。
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)

class LocalSocketService {

    public:int connect_fd = -1;
    private:pthread_t mThreadRecv;//接收线程

    static void *recvCB(void* parm){
        auto client = (LocalSocketService*)parm;
        char recv_buff[1024];

        while (!(client->isClose())){
            memset(recv_buff,0,1024);
            int num = recv(client->connect_fd,recv_buff, sizeof(recv_buff),0);
            if (num < 0){
                LOGI("服务端数据接收错误，检查连接是否正常：%d",num);
            }else{
                LOGI("服务端收到数据内容:%s",recv_buff);
            }
        }
    }

    public:void doAccept(const char address[]){
        int fd = socket(AF_UNIX,SOCK_STREAM,0);
        if (fd < 0){
            LOGI("init socket fail");
            return;
        }

        sockaddr_un srv_addr{};
        memset(&srv_addr,0,sizeof(srv_addr));
        srv_addr.sun_path[0] = '\0';
        strcpy(srv_addr.sun_path + 1, address);
        srv_addr.sun_family = AF_UNIX;

        int nameLen = strlen(address);
        int len = 1 + nameLen + offsetof(struct sockaddr_un, sun_path);

        int ret = bind(fd,(struct sockaddr*)&srv_addr, len);
        if (ret != 0){
            LOGI("bind socket fail");
            return;
        }

        ret = listen(fd,10);
        if (ret != 0){
            LOGI("listener socket fail");
            return;
        }
        sockaddr_un clientAddr{};
        socklen_t clen = sizeof(sockaddr_un);
        LOGI("start accept");

        //考虑到这只是一个sample，避免写得过于复杂，这里只考虑连接一个客户端的情况，不作循环一直等待
        connect_fd = accept(fd,(struct sockaddr*)&clientAddr,&clen);
        LOGI("connect client success");

        if (connect_fd != -1){
            pthread_create(&mThreadRecv,NULL,recvCB,this);
        }
    }

    public:bool isClose(){
        return connect_fd <= 0;
    }

    public:void send(char msg[]){
        ::send(connect_fd,msg, strlen(msg),0);
    }
};
